# -*-coding:utf-8 -*-
import os
import tree_sitter_related as ts
import process_file as pf

'''
扩充原则: 根据assert语句扩充
匹配原则: 名字匹配 且 (焦点方法名必须在调用列表中出现 或 在assert语句中出现)
'''

directory = '../../crates_crawler/crates/'
TF_and_FUT_root = '../result/TF_FUT/'
TF_miss_root = '../result/TF_miss/'
os.makedirs(TF_and_FUT_root, exist_ok=True)
os.makedirs(TF_miss_root, exist_ok=True)
succeed_dir_num = 0

total_num = 0
strict_match_num = 0
miss_num = 0

if __name__ == '__main__':
    subdirectories = pf.get_first_level_subdirectories(directory)
    for dir_path in subdirectories:
        num_id = 1
        dict_PATH = {}
        dir_name = pf.get_last_directory_name(dir_path)

        list_node_total_function = []
        list_node_test_function = []
        list_TF_and_FUT = []
        list_TF_miss = []

        # 查找项目下的所有rs文件，找到所有test and function_item
        for root, dirs, files in os.walk(dir_path):
            for filename in files:
                file_path = os.path.join(root, filename)
                file_path = pf.path_normalized(file_path)

                if os.path.isfile(file_path) and filename.endswith('.rs'):
                    rust_code = pf.read_rust_code(file_path)
                    root_node = ts.get_root_node(rust_code)

                    # 找到所有#[test]而非cfg test
                    list_node_test_function_temp = ts.get_list_node_test_function(root_node)

                    # 找到所有function_item
                    list_node_total_function_temp = ts.get_list_node_total_function(root_node)
                    for node in list_node_total_function_temp:
                        dict_PATH[id(node)] = file_path
                    list_node_total_function.extend(list_node_total_function_temp)


                    if list_node_test_function_temp:
                        for node in list_node_test_function_temp:
                            dict_PATH[id(node)] = file_path
                        list_node_test_function.extend(list_node_test_function_temp)


        # 去重list_node_total_function,(函数名，参数数量)都相同则去掉
        dict_unique_node_function = ts.get_dict_unique_node_function_item(list_node_total_function)

        if not list_node_test_function:
            continue
        # 删除dict_unique_node_function中的测试函数
        for node_test_function in list_node_test_function:
            if not node_test_function or node_test_function.type != 'function_item':
                continue
            name_test_function = ts.get_function_name(node_test_function)
            cnt_para_num = ts.get_function_para_count(node_test_function)
            if (name_test_function, cnt_para_num) in dict_unique_node_function:
                del dict_unique_node_function[(name_test_function, cnt_para_num)]


        # 根据assert语句扩充list_node_test_function
        list_node_test_function_by_assert = []
        for node_test_function in list_node_test_function:
            list_node_test_function_by_assert_temp = ts.get_list_node_function_by_assert(node_test_function)
            list_node_test_function_by_assert.extend(list_node_test_function_by_assert_temp)

            # 添加路径信息
            for node in list_node_test_function_by_assert_temp:
                dict_PATH[id(node)] = dict_PATH[id(node_test_function)]

        # 下面的node_test_function确保只有一条assert语句
        for node_test_function in list_node_test_function_by_assert:
            if not node_test_function or node_test_function.type != 'function_item':
                continue

            total_num += 1

            # 1 必须完全匹配，如果有test_或_test则删除掉后再进行匹配，且必须再调用中出现过
            list_node_call_expression = ts.get_list_node_call_expression(node_test_function)
            node_assert = ts.get_first_node_assert(node_test_function)
            list_name_and_paranum = []
            if node_assert:
                str_assert = node_assert.text.decode('utf-8')
                dict_substr_num = {}
                list_name_and_paranum = ts.get_list_name_and_paranum(node_assert, str_assert, dict_substr_num)



            list_name_call_expression = []
            for node_call_expression in list_node_call_expression:
                name_call_ex = ts.get_call_expression_name(node_call_expression)
                list_name_call_expression.append(name_call_ex)


            name_test_function = ts.get_function_name(node_test_function)

            if name_test_function.startswith("test_"):
                name_test_function = name_test_function[len("test_"):]
                # 去掉后缀'_test'
            if name_test_function.endswith("_test"):
                name_test_function = name_test_function[:-len("_test")]
            # 焦点方法名（name_test_function）必须在调用列表中出现 或者 在assert语句中出现
            if name_test_function in list_name_call_expression or any(item[0] == name_test_function for item in list_name_and_paranum):
                for key in dict_unique_node_function.keys():
                    if key[0] == name_test_function:
                        strict_match_num += 1
                        # 保存信息
                        node_FUT = dict_unique_node_function[key]

                        dict_TF_and_FUT = {}
                        dict_TF_and_FUT['id'] = str(num_id).zfill(4)
                        num_id += 1

                        dict_TF_and_FUT['FUT_name'] = ts.get_function_name(node_FUT)
                        dict_TF_and_FUT['FUT_para_list'] = ts.get_function_para_list(node_FUT)
                        dict_TF_and_FUT['FUT_para_count'] = ts.get_function_para_count(node_FUT)
                        dict_TF_and_FUT['FUT_return_type'] = ts.get_function_return_type(node_FUT)
                        dict_TF_and_FUT['FUT_full'] = node_FUT.text.decode('utf-8')
                        dict_TF_and_FUT['FUT_path'] = dict_PATH[id(node_FUT)]

                        dict_TF_and_FUT['TF_name'] = ts.get_function_name(node_test_function)
                        dict_TF_and_FUT['TF_full'] = node_test_function.text.decode('utf-8')
                        dict_TF_and_FUT['TF_path'] = dict_PATH[id(node_test_function)]

                        ## 保存匹配方式
                        dict_TF_and_FUT['match_pattern'] = 'strict_match'
                        list_TF_and_FUT.append(dict_TF_and_FUT)
                        break

            # 匹配不成功, 保存匹配失败的测试函数
            miss_num += 1
            dict_TF_miss = {}
            dict_TF_miss['TF_name'] = ts.get_function_name(node_test_function)
            dict_TF_miss['TF_full'] = node_test_function.text.decode('utf-8')
            dict_TF_miss['TF_path'] = dict_PATH[id(node_test_function)]
            dict_TF_miss['match_pattern'] = 'miss'

            list_TF_miss.append(dict_TF_miss)


        # 保存
        save_path = f'{TF_and_FUT_root}{dir_name}.json'
        save_path_miss = f'{TF_miss_root}{dir_name}.json'

        if len(list_TF_and_FUT) != 0:
            pf.save_data_to_json(list_TF_and_FUT, save_path)
        if len(list_TF_miss) != 0:
            pf.save_data_to_json(list_TF_miss, save_path_miss)

        succeed_dir_num += 1
        print(f"{succeed_dir_num} {dir_name} - match: {len(list_TF_and_FUT)}, miss: {len(list_TF_miss)} success!!!")



    print(f"strict match num: {strict_match_num}")
    print(f"miss num: {miss_num}")
    print(f"total num: {total_num}")